package com.thinkingcoder.tcgateway.plugin;

import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;

import com.thinkingcoder.tcgateway.plugin.chain.GatewayPluginChain;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Component("directPlugin")
public class DirectPlugin extends AbstractGatewayPlugin {

    public static final String NAME = "Direct-Plugin";

    public static final String CONTEXT = "direct";

    @Override
    public String getName() {
        return NAME;
    }

    @Override
    public String getContext() {
        return CONTEXT;
    }

    @Override
    public boolean doSupport(ServerWebExchange exchange) {
        return exchange.getRequest().getPath().value().startsWith(getPrefix());
    }

    @Override
    public Mono<Void> doHandle(ServerWebExchange exchange, GatewayPluginChain chain) {
        System.out.println(" ===>>> [DirectPlugin] ...");
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String backend = request.getQueryParams().getFirst("backend");
        Flux<DataBuffer> requestBody = request.getBody();

        response.getHeaders().add("Content-Type", "application/json");
        response.getHeaders().add("tc.gateway.version", "v1.0.0");
        response.getHeaders().add("tc.gateway.plugin", getName());

        if (backend == null || backend.isEmpty()) {
            return requestBody.flatMap(x -> response.writeWith(Mono.just(x))).then(chain.handle(exchange));
        }

        WebClient client = WebClient.create(backend);
        Mono<ResponseEntity<String>> entity = client.post().header("Content-Type", "application/json")
            .body(requestBody, DataBuffer.class).retrieve().toEntity(String.class);
        Mono<String> body = entity.map(ResponseEntity::getBody);

        return body.flatMap(x -> response.writeWith(Mono.just(response.bufferFactory().wrap(x.getBytes()))))
            .then(chain.handle(exchange));
    }
}
